home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / comm / tcp / AmigaTCP.lha / AmigaTCP / src / icmp.c < prev    next >
C/C++ Source or Header  |  1989-06-24  |  7KB  |  311 lines

  1. /* Internet Control Message Protocol */
  2.  
  3. #include "machdep.h"
  4. #include "internet.h"
  5. #include "timer.h"
  6. #include "ip.h"
  7. #include "icmp.h"
  8. #include "mbuf.h"
  9.  
  10. int (*echo_proc)();    /* Handler for Echo Reply messages */
  11.  
  12. struct icmp_errors icmp_errors;
  13. struct icmp_stats icmp_stats;
  14.  
  15. /* Process an incoming ICMP packet */
  16. void
  17. icmp_input(bp,protocol,source,dest,tos,length,rxbroadcast)
  18. struct mbuf *bp;    /* Pointer to ICMP message */
  19. char protocol;        /* Should always be ICMP_PTCL */
  20. int32 source;        /* Sender of ICMP message */
  21. int32 dest;        /* Us */
  22. char tos;        /* Type of Service */
  23. int16 length;        /* Length of ICMP message */
  24. char rxbroadcast;
  25. {
  26.  
  27.     struct icmp *icmph;    /* Pointer to ICMP message */
  28.     struct ip_header *iph;    /* Offending datagram header */
  29.     int16 type;        /* Type of ICMP message */
  30.     int16 ip_len;
  31.  
  32.     if(rxbroadcast){
  33.         /* Broadcast ICMP packets are to be IGNORED !! */
  34.         icmp_errors.bdcsts++;
  35.         free_p(bp);
  36.         return;
  37.     }
  38.     if(cksum(NULLHEADER,bp,length) != 0){
  39.         /* Bad ICMP checksum; discard */
  40.         icmp_errors.checksum++;
  41.         free_p(bp);
  42.         return;
  43.     }
  44.     /* If the message is fragmented, copy to a contiguous mbuf */
  45.     if(bp->next != NULLBUF){
  46.         struct mbuf *nbp;
  47.  
  48.         nbp = copy_p(bp,length);
  49.         free_p(bp);
  50.         if(nbp == NULLBUF){
  51.             icmp_errors.nospace++;
  52.             return;
  53.         }
  54.         bp = nbp;
  55.     }
  56.     icmph = (struct icmp *)bp->data;
  57.  
  58.     /* Process the message. Some messages are passed up to the protocol
  59.      * module for handling, others are handled here.
  60.      */
  61.     type = icmph->type & 0xff;
  62.     if(type < ICMP_TYPES)
  63.         icmp_stats.input[type]++;
  64.  
  65.     switch(type){
  66.     case TIME_EXCEED:    /* Time-to-live Exceeded */
  67.     case DEST_UNREACH:    /* Destination Unreachable */
  68.     case QUENCH:        /* Source Quench */
  69.         iph = (struct ip_header *)(icmph + 1);
  70.         ip_len = (iph->v_ihl & 0xf) * sizeof(int32);
  71.  
  72.         switch(iph->protocol){
  73.         case TCP_PTCL:
  74.             tcp_icmp(ntohl(iph->source),ntohl(iph->dest),
  75.                 icmph->type,icmph->code,(char *)iph + ip_len);
  76.             break;
  77.         }
  78.         break;
  79.     case ECHO:        /* Echo Request */
  80.         /* Change type to ECHO_REPLY, recompute checksum,
  81.          * and return datagram.
  82.          */
  83.         icmph->type = ECHO_REPLY;
  84.         icmph->checksum = 0;
  85.         icmph->checksum = cksum(NULLHEADER,bp,length);
  86.         icmp_stats.output[ECHO_REPLY]++;
  87.         ip_send(dest,source,ICMP_PTCL,tos,0,bp,length,0,0);
  88.         return;
  89.     case REDIRECT:        /* Redirect */
  90.     case PARAM_PROB:    /* Parameter Problem */
  91.         break;
  92.        case ECHO_REPLY:        /* Echo Reply */
  93.         if(echo_proc){
  94.             (*echo_proc)(ntohl(iph->source),ntohl(iph->dest),
  95.              icmph->type,icmph->code,(char *)iph + ip_len);
  96.         }
  97.         break;
  98.     case TIMESTAMP:        /* Timestamp */
  99.     case TIME_REPLY:    /* Timestamp Reply */
  100.     case INFO_RQST:        /* Information Request */
  101.     case INFO_REPLY:    /* Information Reply */
  102.         break;
  103.     }
  104.     free_p(bp);
  105. }
  106. /* Return an ICMP response to the sender of a datagram */
  107. icmp_output(bp,type,code,args)
  108. struct mbuf *bp;        /* Pointer to offending IP header + data */
  109. char type,code;            /* Codes to send */
  110. union icmp_args *args;
  111. {
  112.     struct ip_header *iph;    /* Offending IP header */
  113.     int16 ip_len;        /* Length of offending IP header */
  114.  
  115.     struct mbuf *reply;    /* Buffer with ICMP reply */
  116.     struct icmp *icmph;    /* ICMP protocol header */
  117.     struct mbuf *data;    /* Returned portion of offending packet */
  118.     int16 dlen;        /* Length of data portion of offending pkt */
  119.     int16 length;        /* Total length of reply */
  120.     extern int32 ip_addr;    /* Our IP address */
  121.  
  122.     if(type < ICMP_TYPES)
  123.         icmp_stats.output[type]++;
  124.  
  125.     iph = (struct ip_header *)bp->data;
  126.  
  127.     if(iph->protocol == ICMP_PTCL){
  128.         icmp_errors.noloop++;
  129.         return;    /* Never send an ICMP message about another ICMP message */
  130.     }
  131.     /* Compute amount of original datagram to return.
  132.      * We return the original IP header, and up to 8 bytes past that.
  133.      */
  134.     ip_len = (iph->v_ihl & 0xf) * sizeof(int32);
  135.     dlen = ntohs(iph->length);
  136.     if(dlen > ip_len + 8)
  137.         dlen = ip_len + 8;
  138.     length = sizeof(struct icmp) + dlen;
  139.  
  140.     /* Allocate ICMP header and fill in */
  141.     if((reply = alloc_mbuf(sizeof(struct icmp))) == NULLBUF){
  142.         /* No space; don't bother */
  143.         icmp_errors.nospace++;
  144.         return;
  145.     }
  146.     reply->cnt = sizeof(struct icmp);
  147.     icmph = (struct icmp *)reply->data;
  148.     icmph->type = type;
  149.     icmph->code = code;
  150.     if(args != (union icmp_args *)NULL)
  151.         icmph->args.unused = args->unused;    /* copies whole union */
  152.     else
  153.         icmph->args.unused = 0;
  154.  
  155.     /* Link in a copy of the beginning of the original datagram */
  156.     data = copy_p(bp,dlen);
  157.     reply->next = data;    /* Could be NULL if copy fails */
  158.  
  159.     /* Compute ICMP checksum and send */
  160.     icmph->checksum = 0;
  161.     icmph->checksum = cksum(NULLHEADER,reply,length);
  162.  
  163.     ip_send(ip_addr,ntohl(iph->source),ICMP_PTCL,iph->tos,0,reply,length,0,0);
  164. }
  165. #ifdef    TRACE
  166. /* ICMP message types */
  167. char *icmptypes[] = {
  168.     "Echo Reply",
  169.     NULLCHAR,
  170.     NULLCHAR,
  171.     "Unreachable",
  172.     "Source Quench",
  173.     "Redirect",
  174.     NULLCHAR,
  175.     NULLCHAR,
  176.     "Echo Request",
  177.     NULLCHAR,
  178.     NULLCHAR,
  179.     "Time Exceeded",
  180.     "Parameter Problem",
  181.     "Timestamp",
  182.     "Timestamp Reply",
  183.     "Information Request",
  184.     "Information Reply"
  185. };
  186.  
  187. /* ICMP unreachable messages */
  188. char *unreach[] = {
  189.     "Network",
  190.     "Host",
  191.     "Protocol",
  192.     "Port",
  193.     "Fragmentation",
  194.     "Source route"
  195. };
  196. /* ICMP Time exceeded messages */
  197. char *exceed[] = {
  198.     "Time-to-live",
  199.     "Fragment reassembly"
  200. };
  201.  
  202. /* ICMP redirect messages */
  203. char *redirect[] = {
  204.     "Network",
  205.     "Host",
  206.     "TOS & Network",
  207.     "TOS & Host"
  208. };
  209.  
  210. int
  211. doicmpstat(argc,argv)
  212. int argc;
  213. char *argv[];
  214. {
  215.     extern struct icmp_errors icmp_errors;
  216.     extern struct icmp_stats icmp_stats;
  217.     register int i;
  218.  
  219.     printf("chksum err %u no space %u icmp %u bdcsts %u\r\n",
  220.      icmp_errors.checksum,icmp_errors.nospace,icmp_errors.noloop,
  221.      icmp_errors.bdcsts);
  222.     printf("type  rcvd  sent\r\n");
  223.     for(i=0;i<ICMP_TYPES;i++){
  224.         if(icmp_stats.input[i] == 0 && icmp_stats.output[i] == 0)
  225.             continue;
  226.         printf("%-6u%-6u%-6u",i,icmp_stats.input[i],
  227.             icmp_stats.output[i]);
  228.         if(icmptypes[i] != NULLCHAR)
  229.             printf("  %s",icmptypes[i]);
  230.         printf("\r\n");
  231.     }
  232.     return 0;
  233. }
  234. /* Dump an ICMP header */
  235. void
  236. icmp_dump(bp,source,dest,check)
  237. struct mbuf *bp;
  238. int32 source,dest;
  239. int check;        /* If 0, bypass checksum verify */
  240. {
  241.     register struct icmp *icmp;
  242.     char *codemsg;
  243.     struct mbuf *ibp;
  244.     int i;
  245.     char tmpbuf;
  246.  
  247.     if(bp == NULLBUF)
  248.         return;
  249.     /* If packet isn't in a single buffer, make a temporary copy and
  250.      * note the fact so we free it later
  251.      */
  252.     if(bp->next != NULLBUF){
  253.         bp = copy_p(bp,len_mbuf(bp));
  254.         tmpbuf = 1;
  255.     } else
  256.         tmpbuf = 0;
  257.  
  258.     codemsg = NULLCHAR;
  259.     icmp = (struct icmp *)bp->data;
  260.     if(icmp->type <= 16 && icmptypes[icmp->type] != NULLCHAR)
  261.         printf("ICMP: %s",icmptypes[icmp->type]);
  262.     else
  263.         printf("ICMP: type %u",icmp->type);
  264.  
  265.     switch(icmp->type){
  266.     case DEST_UNREACH:
  267.         if(icmp->code <= 5)
  268.             codemsg = unreach[icmp->code];
  269.         break;
  270.     case REDIRECT:
  271.         if(icmp->code <= 3)
  272.             codemsg = redirect[icmp->code];
  273.         break;
  274.     case TIME_EXCEED:
  275.         if(icmp->code <= 1)
  276.             codemsg = exceed[icmp->code];
  277.         break;
  278.     }    
  279.     if(codemsg != NULLCHAR)
  280.         printf(" %s",codemsg);
  281.     else
  282.         printf(" code %u",icmp->code);
  283.  
  284.     /* Special case for parameter problem message */
  285.     if(icmp->type == PARAM_PROB)
  286.         printf(" pointer = 0x%x",icmp->args.pointer);
  287.  
  288.     if(check){
  289.         /* Verify checksum */
  290.         if((i = cksum(NULLHEADER,bp,len_mbuf(bp))) != 0)
  291.             printf(" CHECKSUM ERROR (%u)",i);
  292.     }
  293.     printf("\r\n");
  294.     /* Dump the offending IP header, if any */
  295.     switch(icmp->type){
  296.     case DEST_UNREACH:
  297.     case TIME_EXCEED:
  298.     case PARAM_PROB:
  299.     case QUENCH:
  300.     case REDIRECT:
  301.         printf("Returned ");
  302.         dup_p(&ibp,bp,sizeof(struct icmp),
  303.             len_mbuf(bp) - sizeof(struct icmp));
  304.         ip_dump(ibp);
  305.         free_p(ibp);
  306.     }
  307.     if(tmpbuf)
  308.         free_p(bp);
  309. }
  310. #endif
  311.